package cn.bellychang.ood.litejunit.v3.framework.runners;

import cn.bellychang.ood.litejunit.v3.framework.notification.Failure;
import cn.bellychang.ood.litejunit.v3.framework.notification.RunListener;
import cn.bellychang.ood.litejunit.v3.framework.runner.Description;
import cn.bellychang.ood.litejunit.v3.framework.runner.Result;

import java.io.PrintStream;
import java.text.NumberFormat;

/**
 * @author ChangLiang
 * @date 2020/5/28
 */
public class TextListener extends RunListener {

    private final PrintStream writer;

    public TextListener() {
        this(System.out);
    }

    public TextListener(PrintStream writer) {
        this.writer = writer;
    }

    @Override
    public void testRunFinished(Result result) throws Exception {
        printHeader(result.getRunTime());
        printFailures(result);
        printFooter(result);
    }

    @Override
    public void testRunStarted(Description description) throws Exception {
        writer.append('.');
    }

    @Override
    public void testFailure(Failure failure) throws Exception {
        writer.append('E');
    }

    @Override
    public void testIgnored(Description description) throws Exception {
        writer.append('I');
    }

    /*
     * Internal methods
     */

    private PrintStream getWriter() {
        return writer;
    }

    private void printFooter(Result result) {
        if (result.wasSuccessful()) {
            getWriter().println();
            getWriter().print("OK");
            getWriter().println(" (" + result.getRunCount() + " test" + (result.getRunCount() == 1 ? "" : "s") + ")");

        } else {
            getWriter().println();
            getWriter().println("FAILURES!!!");
            getWriter().println("Tests run: " + result.getRunCount() + ",  Failures: " + result.getFailureCount());
        }
        getWriter().println();
    }

    private void printHeader(long runTime) {
        getWriter().println();
        getWriter().println("Time: " + elapsedTimeAsString(runTime));
    }

    private void printFailures(Result result) {
        if (result.getFailureCount() == 0) {
            return;
        }
        if (result.getFailureCount() == 1) {
            getWriter().println("There was " + result.getFailureCount() + " failure:");
        } else {
            getWriter().println("There were " + result.getFailureCount() + " failures:");
        }
        int i= 1;
        for (Failure each : result.getFailures()) {
            printFailure(each, i++);
        }
    }

    private void printFailure(Failure failure, int count) {
        printFailureHeader(failure, count);
        printFailureTrace(failure);
    }

    protected void printFailureHeader(Failure failure, int count) {
        getWriter().println(count + ") " + failure.getTestHeader());
    }

    protected void printFailureTrace(Failure failure) {
        getWriter().print(failure.getTrace());
    }

    /**
     * Returns the formatted string of the elapsed time. Duplicated from
     * BaseTestRunner. Fix it.
     */
    protected String elapsedTimeAsString(long runTime) {
        return NumberFormat.getInstance().format((double) runTime / 1000);
    }
}
